﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.Web;
using SecurityClient;

namespace SecurityModule.Workflows
{
    class WFPostHomeLogin : SimpleWorkflow
    {
        public WFPostHomeLogin()
        {
            Verb = "POST";
            Path = "/Home/Login";
        }

        public override void PreProcessImplementation(HttpContext context)
        {
            var errorMessage = "";
            //Read raw values from input filter, perform login, and rewrite password
            var requestCallback = new Func<string, string>(content =>
            {
                //We should expect a form post, which will be a querystring.

                //Read the form fields and white list them.
                var fields = HttpUtility.ParseQueryString(content);

                //Read fields
                var username = fields["Username"];
                var email = fields["Email"];
                var password = fields["Password"];
                var yubikeyOTP = fields["YubikeyOTP"];

                //Whitelist the following fields to prevent password from being sidebanded.
                string[] whitelistFields = { "Email", "Password" };
                foreach (var key in fields.AllKeys.Where(key => !whitelistFields.Contains(key)))
                {
                    fields.Remove(key);
                }

                //Login
                //In this application username is email
                if (string.IsNullOrEmpty(username))
                    username = email;

                try
                {
                    var security = new SecurityServiceProxy();
                    var loginResult = security.Login(username, password, yubikeyOTP);
                    if (loginResult.Success)
                    {
                        //rewrite password
                        fields["Password"] = loginResult.Password;
                    }
                    else
                    {
                        fields["Password"] = "error";
                        errorMessage = loginResult.ErrorMessage;
                    }
                }
                catch (Exception exception)
                {
                    if (exception is PipeException || exception is EndpointNotFoundException)
                    {
                        //If the security service is offline or broken
                        if (fields.AllKeys.Contains("EXTERRMSG"))
                        {
                            fields["EXTERRMSG"] = SecurityServiceDownMsg;
                        }
                        else
                        {
                            fields.Add("EXTERRMSG", SecurityServiceDownMsg);
                        }
                    }
                    else
                    {
                        if (fields.AllKeys.Contains("EXTERRMSG"))
                        {
                            fields["EXTERRMSG"] = exception.Message;
                        }
                        else
                        {
                            fields.Add("EXTERRMSG", exception.Message);
                        }
                    }
                }
                //write out the whitelisted fields
                content = fields.ToString();
                return content;
            });
            context.Request.Filter = new RequestFilter(context.Request.Filter, context.Request.ContentEncoding, requestCallback);

            //var dummy = context.Request.Form["dummy"]; // evaluate the request
            if (!string.IsNullOrEmpty(errorMessage))
                AddToForm(context.Request, new Dictionary<string, string>
                    {
                        {"EXTERRMSG", errorMessage},
                    });


            //inject YubikeyOTP input using replace
            context.Response.Filter = new ReplaceFilter(context.Response.Filter, context.Response.ContentEncoding,
                content
                                                        =>
                {
                    content = content.Replace("{{YubikeyOTP}}",
                                    @"<label class='control-label' for='YubikeyOTP'>Yubikey</label><input name='YubikeyOTP' type='text' class='form-control'>");

                    return content;
                });

        }

        public override void PostProcessImplementation(HttpContext context)
        {
            // If statuscode != 200 then log them out?  e.g. if the app enforced administrative lockout.
            if (context.Response.StatusCode == 200 || context.Response.StatusCode == 302) return;
            try
            {
                var security = new SecurityServiceProxy();
                security.Logout();
            }
            // ReSharper disable EmptyGeneralCatchClause
            catch
            // ReSharper restore EmptyGeneralCatchClause
            {
                //If the security service is offline or broken then swallow the exception
            }
        }
    }
}
